/*
Copyright (c) 2009-2010, Warwick Warp Limited
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the Warwick Warp Limited nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL WARWICK WARP LIMITED BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef WARRAY_WARRAY_BYVAL_H_INCLUDED
#define WARRAY_WARRAY_BYVAL_H_INCLUDED

#include "warray_nd.h"

namespace warp {

/*!
	\brief An N-dimensional array class with pass-by-value semantics
	
	Whenever it is assigned to an arraynd_byval copies the assigned data, 
	rather than taking a reference. It is still possible to take references 
	to an arraynd_byval via conversion to arraynd or const_arraynd classes.
	
	There is no implementation of an arraynd_byval for constant data, because 
	there ought to be no need for one (a const_arraynd with pass-by-reference 
	semantics should be sufficient).
	
	This class is primarily intended for member variables of classes that should 
	have pass-by-value semantics.
	
	One potential problem with this implementation is as follows. Consider a
	function
	\code
	void f(array_nd<T,N>& out)
	{
		// ... compute result ...
		out = result;
	}
	\endcode
	if you pass in an arraynd_byval to this function
	\code
	arraynd_byval<T,N> my_array;
	f(my_array);
	\endcode
	then result will not be copied because the wrong version of the assignment 
	operator will be called. This is not easily avoided, so best to be 
	careful when converting arraynd_byval to arraynd.
	
*/
template<typename T, detail::warray_types::size_type NUM_DIMS>
class arraynd_byval : public arraynd<T,NUM_DIMS>
{
	typedef arraynd<T,NUM_DIMS> super_type; 
public:
	typedef typename super_type::value_type      value_type;
	typedef typename super_type::size_type       size_type;
	typedef typename super_type::index_type      index_type;
	typedef typename super_type::const_reference const_reference;
	typedef typename super_type::const_iterator  const_iterator;
	typedef typename super_type::extents_type    extents_type;
	typedef typename super_type::reference       reference;
	typedef typename super_type::iterator        iterator; 
	
	explicit arraynd_byval() :
		super_type()
	{
	}
	
	explicit arraynd_byval(const extents_type& extents) :
		super_type(extents)
	{
	}
	
	explicit arraynd_byval(const extents_type& extents, const T& fillv) :
		super_type(extents,fillv)
	{
	}
	
	explicit arraynd_byval(const extents_type& extents, T *carray_) :
		super_type( super_type(extents,carray_).copy() )
	{
	}
	
	// Implicit conversion is allowed from any array type because we copy
	template<typename Tptr>
	arraynd_byval(const const_arraynd<T,NUM_DIMS,Tptr>& base) :
		super_type(base.copy())
	{
	}
	
	arraynd_byval(const arraynd_byval<T,NUM_DIMS>& base) :
		super_type(base.copy())
	{
	}
	
	// Assignment is allowed from any array type because we copy
	template<typename Tptr>
	arraynd_byval<T,NUM_DIMS>& operator=(const const_arraynd<T,NUM_DIMS,Tptr>& base)
	{
		super_type::operator=(base.copy());
		return *this;
	}
	
	arraynd_byval<T,NUM_DIMS>& operator=(const arraynd_byval<T,NUM_DIMS>& base)
	{
		super_type::operator=(base.copy());
		return *this;
	}	
};

} // namespace warp

#endif
